﻿using CoachingOrganizer.Logic.Models.Tools.MoneyCalculation;
using CoachingOrganizer.Toolkit.Collections.Helpers;
using CoachingOrganizer.Toolkit.Events;
using CoachingOrganizer.WinPhone.UITools;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace CoachingOrganizer.WinPhone.ViewModels.Tools.MoneyCalculation
{
    public class MoneyFlowViewModel : ViewModelBase
    {
        private readonly MoneyFlowModel _model;
        private ObservableCollection<StableMoneyFlowItemViewModel> _stableItems;
        private ObservableCollection<OccasionalMoneyFlowItemViewModel> _occasionalItems;
        private string _newStableItemName;
        private string _newOccasionalItemName;
        private string[] _stableItemsNameSuggestions;
        private string[] _occasionalItemsNameSuggestions;

        public ObservableCollection<StableMoneyFlowItemViewModel> StableItems
        {
            get { return _stableItems; }
        }

        public ObservableCollection<OccasionalMoneyFlowItemViewModel> OccasionalItems
        {
            get { return _occasionalItems; }
        }

        public string NewStableItemName
        {
            get { return _newStableItemName; }
            set
            {
                if (_newStableItemName != value)
                {
                    _newStableItemName = value;
                    RefreshStableItemsNameSuggestions();
                    OnCommandCanExecuteChanged(() => AddNewStableItemCommand);
                }
            }
        }

        public string NewOccasionalItemName
        {
            get { return _newOccasionalItemName; }
            set
            {
                if (_newOccasionalItemName != value)
                {
                    _newOccasionalItemName = value;
                    RefreshOccasionalItemsNameSuggestions();
                    OnCommandCanExecuteChanged(() => AddNewOccasionalItemCommand);
                }
            }
        }

        public string[] StableItemsNameSuggestions
        {
            get { return _stableItemsNameSuggestions; }
        }

        public string[] OccasionalItemsNameSuggestions
        {
            get { return _occasionalItemsNameSuggestions; }
        }

        public ICommand AddNewStableItemCommand
        {
            get { return GetCommand(() => AddNewStableItemCommand, () => AddNewStableItem(), () => !string.IsNullOrWhiteSpace(_newStableItemName)); }
        }

        public ICommand AddNewOccasionalItemCommand
        {
            get { return GetCommand(() => AddNewOccasionalItemCommand, () => AddNewOccasionalItem(), () => !string.IsNullOrWhiteSpace(_newOccasionalItemName)); }
        }

        public MoneyFlowViewModel(MoneyFlowModel model)
        {
            _model = model;
            model.StableMoneyFlowItemsCollectionChanged += Model_StableMoneyFlowItemsCollectionChanged;
            model.OccasionalMoneyFlowItemsCollectionChanged += Model_OccasionalMoneyFlowItemsCollectionChanged;
            ReplaceStableItems();
            ReplaceOccasionalItems();
            RefreshStableItemsNameSuggestions();
            RefreshOccasionalItemsNameSuggestions();
        }

        private void ReplaceStableItems()
        {
            IEnumerable<StableMoneyFlowItemModel> stableItems = _model.StableItems;
            _stableItems = stableItems == null ? null : new ObservableCollection<StableMoneyFlowItemViewModel>(stableItems.Select(m => new StableMoneyFlowItemViewModel(m)));
        }

        private void ReplaceOccasionalItems()
        {
            IEnumerable<OccasionalMoneyFlowItemModel> occasionalItems = _model.OccasionalItems;
            _occasionalItems = occasionalItems == null ? null : new ObservableCollection<OccasionalMoneyFlowItemViewModel>(occasionalItems.Select(m => new OccasionalMoneyFlowItemViewModel(m)));
        }

        private void RefreshStableItemsNameSuggestions()
        {
            ActionResult<IEnumerable<MoneyFlowItemNameSuggestionModel>> suggestionsResult = _model.EnumerateStableItemsNameSuggestions();
            if (suggestionsResult.IsValid && suggestionsResult.Result != null)
            {
                if (!string.IsNullOrWhiteSpace(_newStableItemName))
                    _stableItemsNameSuggestions = suggestionsResult.Result.Where(m => m.SuggestedName.StartsWith(_newStableItemName)).OrderByDescending(m => m.Frequency).Select(m => m.SuggestedName).ToArray();
                else
                    _stableItemsNameSuggestions = suggestionsResult.Result.OrderByDescending(m => m.Frequency).Select(m => m.SuggestedName).ToArray();
                OnPropertyChanged(() => StableItemsNameSuggestions);
            }
        }

        private void RefreshOccasionalItemsNameSuggestions()
        {
            ActionResult<IEnumerable<MoneyFlowItemNameSuggestionModel>> suggestionsResult = _model.EnumerateOccasionalItemsNameSuggestions();
            if (suggestionsResult.IsValid && suggestionsResult.Result != null)
            {
                if (!string.IsNullOrWhiteSpace(_newOccasionalItemName))
                    _occasionalItemsNameSuggestions = suggestionsResult.Result.Where(m => m.SuggestedName.StartsWith(_newOccasionalItemName)).OrderByDescending(m => m.Frequency).Select(m => m.SuggestedName).ToArray();
                else
                    _occasionalItemsNameSuggestions = suggestionsResult.Result.OrderByDescending(m => m.Frequency).Select(m => m.SuggestedName).ToArray();
                OnPropertyChanged(() => OccasionalItemsNameSuggestions);
            }
        }

        private async void AddNewStableItem()
        {
            ActionResult result = await _model.AddNewStableMoneyFlowItem(_newStableItemName);
            if (!result.IsValid)
                await UIHelper.ShowErrorMessageAsync("");
        }

        private async void AddNewOccasionalItem()
        {
            ActionResult result = await _model.AddNewOccasionalMoneyFlowItem(_newOccasionalItemName);
            if (!result.IsValid)
                await UIHelper.ShowErrorMessageAsync("");
        }

        private void Model_StableMoneyFlowItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            BeginInvokeInUIThread(() => ObservableCollectionHelper.ApplyChangesByNumbers<StableMoneyFlowItemModel, StableMoneyFlowItemViewModel>(e, _stableItems, m => new StableMoneyFlowItemViewModel(m)));
        }

        private void Model_OccasionalMoneyFlowItemsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            BeginInvokeInUIThread(() => ObservableCollectionHelper.ApplyChangesByNumbers<OccasionalMoneyFlowItemModel, OccasionalMoneyFlowItemViewModel>(e, _occasionalItems, m => new OccasionalMoneyFlowItemViewModel(m)));
        }
    }
}
